package com.namazustudios.catfish;

import com.google.inject.TypeLiteral;
import com.namazustudios.catfish.annotation.EntityKey;
import com.namazustudios.catfish.annotation.Property;
import com.namazustudios.catfish.callback.Delete;
import com.namazustudios.catfish.callback.Get;
import com.namazustudios.catfish.callback.LifecycleCallback;
import com.namazustudios.catfish.callback.Put;
import com.namazustudios.catfish.converter.Converter;
import com.namazustudios.catfish.exception.NoSuchTypeException;
import com.namazustudios.catfish.generator.IdentityGenerator;
import com.namazustudios.catfish.provider.ValueProvider;
import com.namazustudios.catfish.validator.Validator;

/**
 * Represents the configuration of the Catfish system. This contains the various
 * mappings of annotated values to the Keys which can be used to get the
 * appropraite object from the Injector.
 * 
 * It is not recommended to access this object directly. Rather, you should bind
 * the appropriate types and let the library do the heavy lifting involved with
 * configuring the library. The various Support TypeListeners will take care of
 * ensuring that this is properly populated.
 * 
 * @author patricktwohig
 * 
 */
public interface Configuration {

	/**
	 * Gets the class for the given Kind, if known to Catfish. If the type is
	 * not known then this will throw an instance of NoSuchTypeException.
	 * 
	 * @param kind
	 *            the kind
	 * @return the Class associated with the kind
	 * @throws NoSuchTypeException
	 *             if the Configuration cannot resolve the kind
	 */
	public Class<?> getClass(String kind) throws NoSuchTypeException;

	/**
	 * Gets a {@link Get} callback with the given name. The type passed to this
	 * method must be annotated with an @Entity annotation.
	 * 
	 * @param type
	 *            the type associated with the callback
	 * @return the Key to the callback
	 */
	public Get<?> getGetCallback(Class<?> type);

	/**
	 * Gets a {@link Put} callback with the given name.The type passed to this
	 * method must be annotated with an @Entity annotation.
	 * 
	 * @param type
	 *            the type associated with the callback
	 * @return the Key to the callback
	 */
	public Put<?> getPutCallback(Class<?> type);

	/**
	 * Gets a {@link Delete} callback with the given name. The type passed to
	 * this method must be annotated with an @Entity annotation.
	 * 
	 * @param type
	 *            the type associated with the callback
	 * @return the Key to the callback
	 */
	public Delete<?> getDeleteCallback(Class<?> name);

	/**
	 * Gets the Key to the {@link Validator} for the given property. The type
	 * passed to this method must be annotated with an @Entity annotation.
	 * 
	 * @param property
	 *            the property
	 * @return the Key or null if no such key exists.
	 */
	public Validator<?> getValidator(Property property);

	/**
	 * Gets the {@link Converter} using the given property.
	 * 
	 * @param property
	 *            the property
	 * @return the Key or null if no such key exists
	 */
	public Converter<?, ?> getConverter(Property property);

	/**
	 * Gets the ValueProvider associated with the property.
	 * 
	 * @param property
	 *            the property
	 * @return the value provider
	 */
	public ValueProvider<?> getValueProvider(Property property);

	/**
	 * Gets the {@link IdentityGenerator} using the given EntityKey annotation.
	 * 
	 * @param key
	 * @return
	 */
	public IdentityGenerator<?> getIdentityGenerator(EntityKey key);

	/**
	 * Adds the given Kind to the configuration. The type passed to this method
	 * must be annotated with an @Entity annotation.
	 * 
	 * @param cls
	 *            the class
	 * 
	 */
	public void addClass(TypeLiteral<?> cls);

	/**
	 * Configures a type of Get callback.
	 * 
	 * @param type
	 *            the key
	 */
	public void addLifecycleCallback(TypeLiteral<? extends LifecycleCallback> type);

	/**
	 * Adds a Converter type to the configuration.
	 * 
	 * @param typeLiteral
	 *            the typeLiteral representing the Converter
	 * 
	 */
	public void addConverter(TypeLiteral<? extends Converter<?, ?>> typeLiteral);

	/**
	 * Configures a Validator type to be used by the system.
	 * 
	 * @param typeLiteral
	 */
	public void addValidator(TypeLiteral<? extends Validator<?>> typeLiteral);

	/**
	 * Configures a ValueProvider type to be used by the system.
	 * 
	 * @param typeLiteral the type literal.
	 */
	public void addValueProvider(TypeLiteral<? extends ValueProvider<?>> typeLiteral);

	/**
	 * Configures an IdentityGenerator type to be used by the system.
	 * 
	 * @param typeLiteral
	 */
	public void addIdentityGenerator(TypeLiteral<? extends IdentityGenerator<?>> typeLiteral);

}
